package edu.tyut.game.controller.game;

import cn.hutool.core.lang.Pair;
import edu.tyut.game.config.SocketConfig;
import edu.tyut.game.model.FlyingFlowerOrderData;
import edu.tyut.game.model.Result;
import edu.tyut.game.model.UserTotalRoundsRank;
import edu.tyut.game.model.UserWinRateRank;
import edu.tyut.game.service.FlyingFlowerOrderService;
import edu.tyut.game.service.PoemService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.io.*;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.*;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;

@Slf4j
@RestController
@RequestMapping("/flyingFlowerOrderGame")
public class FlyingFlowerOrderController {

    @Value("${poems.keywords}")
    private String keywords;
    private List<String> keywordList;
    private String word;
    private final List<FlyingFlowerOrderData> userList = Collections.synchronizedList(new ArrayList<>());
    // uid socket
    private final Map<Integer, Socket> idUserMap = Collections.synchronizedMap(new HashMap<>());

    private PoemService poemService;

    @Autowired
    public void setPoemService(PoemService poemService) {
        keywordList = Arrays.stream(keywords.split("\\s+")).toList();
        log.info(keywordList.toString());
        this.poemService = poemService;
    }

    private FlyingFlowerOrderService orderService;

    @Autowired
    public void setOrderService(FlyingFlowerOrderService orderService) {
        this.orderService = orderService;
    }

    @GetMapping("/getWinRateRank")
    public Result<List<UserWinRateRank>> getWinRateRank(){
        return Result.success("获取胜率排行成功", orderService.getWinRateRank());
    }

    @GetMapping("/getTotalRoundsRank")
    public Result<List<UserTotalRoundsRank>> getTotalRoundsRank(){
        return Result.success("获取总局数排行成功", orderService.getTotalRoundsRank());
    }

    @GetMapping("/getWinRateRankTotalRoundsRank")
    public Result<Pair<List<UserWinRateRank>, List<UserTotalRoundsRank>>> getWinRateRankTotalRoundsRank(){
        return Result.success("获取胜率、总局数排行成功", new Pair<>(orderService.getWinRateRank(), orderService.getTotalRoundsRank()));
    }

    @GetMapping("/getContents/{word}")
    public Result<List<String>> getContents(@PathVariable("word") String word) {
        List<String> words = orderService.getContentsByWord(word);
        return Result.success("获取诗词成功", words);
    }


    @GetMapping("/isExistPoem/{content}")
    public Result<Boolean> isExistPoem(@PathVariable("content") String content) {
        boolean existPoem = poemService.isExistPoem(content);
        log.info("是否存在该诗词：" + existPoem);
        return Result.success("是否存在该诗词？", existPoem);
    }

    @GetMapping("/gameOver/{uid}")
    public Result<Boolean> gameOver(@PathVariable("uid") int uid) {
        // 游戏结束 才进行这一步, 单独抽离一个方法，然后关闭socket资源
        try {
            if (uid != 0) {
                log.info("游戏结束中... : " + uid);
                idUserMap.remove(uid).close();
                log.info("是否还存在socket：" + idUserMap.get(uid));
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return Result.success("游戏结束!", true);
    }

    private SocketConfig socketConfig;
    @Autowired
    public void setSocketConfig(SocketConfig socketConfig) {
        this.socketConfig = socketConfig;
    }

    // 埋点函数
    @GetMapping("/win/{uid}")
    public Result<String> win(@PathVariable("uid") int uid) {
        /*
        flyGame uid 局数 输赢(0,1) 时间戳
        PoemRecommend uid poemId 1
         */
        log.error("flyGame,{},{},{},{}", uid, 1, 1, System.currentTimeMillis());
        socketConfig.writeInfo(String.format("flyGame,%d,%d,%d,%d", uid, 1, 1, System.currentTimeMillis()));
        return Result.success("埋点成功", "埋点成功");
    }
    // 埋点函数
    @GetMapping("/lose/{uid}")
    public Result<String> lose(@PathVariable("uid") int uid) {
        /*
        flyGame uid 局数 输赢(0,1) 时间戳
        PoemRecommend uid poemId 1
         */
        log.error("flyGame,{},{},{},{}", uid, 1, 0, System.currentTimeMillis());
        socketConfig.writeInfo(String.format("flyGame,%d,%d,%d,%d", uid, 1, 0, System.currentTimeMillis()));
        return Result.success("埋点成功", "埋点成功");
    }

    public FlyingFlowerOrderController() {
        log.info("FlyingFlowerOrderController 构造器运行中 ... ");
        new Thread(this::init).start();
        runTask();
    }

    private void init() {
        try (ServerSocket serverSocket = new ServerSocket(7777)) {
            while (true) {
                Socket accept = serverSocket.accept();
                log.info("建立连接...");
                ObjectInputStream ois = new ObjectInputStream(accept.getInputStream());
                int uid = ois.readInt();
                log.info("用户id: " + uid);
                // 数据库读取数据
                FlyingFlowerOrderData flowerOrderUserData = orderService.getFlyingFlowerOrderUserData(uid);
                log.info(flowerOrderUserData.toString());
                userList.add(flowerOrderUserData);
                idUserMap.put(uid, accept);
                log.info("数组大小: " + userList.size());
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    // 排序完成，然后将uid两两放入opponentMap

    private void sendMessage(Socket socket, String str) {
        try {
            ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
            oos.writeUTF(str);
            oos.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    private void sendEachMessage(Socket receive, Socket send, CountDownLatch downLatch) {
        try {
            downLatch.countDown();
            BufferedReader ois = new BufferedReader(new InputStreamReader(receive.getInputStream()));
            BufferedWriter oos = new BufferedWriter(new OutputStreamWriter(send.getOutputStream()));
            String line;
            // 阻塞
            while ((line = ois.readLine()) != null) {
                log.info("sendMessage...");
                log.info("info: " + line);
                oos.write(line);
                oos.newLine();
                oos.flush();
            }
            log.info("发送消息完成！");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public void runTask() {
        Timer timer = new Timer();
        Random random = new Random();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                while (userList.size() >= 2) {
                    log.info("runTask 运行中...");
                    // 根据胜率、总局数权重匹配排序
                    sortByScore();
                    // 匹配对手
                    FlyingFlowerOrderData userData1 = userList.get(userList.size() - 1);
                    FlyingFlowerOrderData userData2 = userList.get(userList.size() - 2);
                    userList.remove(userList.size() - 1);
                    userList.remove(userList.size() - 1);
                    CountDownLatch downLatch = new CountDownLatch(2);
                    new Thread(() -> sendEachMessage(idUserMap.get(userData1.getUid()), idUserMap.get(userData2.getUid()), downLatch)).start();
                    new Thread(() -> sendEachMessage(idUserMap.get(userData2.getUid()), idUserMap.get(userData1.getUid()), downLatch)).start();
                    try {
                        boolean await = downLatch.await(60, TimeUnit.SECONDS);
                        // 匹配成功
                        int indexRandom = random.nextInt(keywordList.size());
                        word = keywordList.get(indexRandom);
                        sendMessage(idUserMap.get(userData1.getUid()), word + " 0x290515");
                        sendMessage(idUserMap.get(userData2.getUid()), word + " 0x290515");
                        log.info("匹配成功，同步完成: " + await);
                    } catch (InterruptedException e) {
                        log.error(e.getMessage());
                        throw new RuntimeException(e);
                    }
                    log.info("数组大小: " + userList.size());
                }
            }
        }, 10000, 10000); // 延期10s, 10s搞一次
    }

    /**
     * 根据比重排序
     */
    private void sortByScore() {
        userList.sort((o1, o2) -> (int) (getWeight(o1) - getWeight(o2)));
    }

    /**
     * 计算排序比重
     *
     * @param userData 用户游戏数据
     * @return 返回比重
     */
    private double getWeight(FlyingFlowerOrderData userData) {
        // return userData.winRate() * 100 * 0.4 + userData.totalRounds() * 0.6;
        return userData.getWinRate() * 100 * 0.4 + userData.getTotalRounds() * 0.6;
    }


    // private final List<User> userList = Collections.synchronizedList(new ArrayList<>());
    // private final Map<User, User> userMap = Collections.synchronizedMap(new HashMap<>());
    //
    // @Async("asyncServiceExecutor")
    // @PostMapping("/match1111111111111111111")
    // public CompletableFuture<Result<User>> match(@RequestBody User user) {
    //     // User userId = userService.getUserByUsername(user.username());
    //     // log.info(userId.toString());
    //     // 根据用户id去获取FlyingFlowerOrderData
    //     // 根据胜率去排序user，然后进行凉凉匹配
    //     // 先实现匹配然后未来实现按照胜率或者对局数匹配
    //     if (userList.contains(user)){
    //         return CompletableFuture.completedFuture(Result.success("已进入匹配队列, 人数不足请等待", null));
    //     }
    //     userList.add(user);
    //
    //     // 根据总局数局数排序
    //     // 放入map
    //     if (userList.size() >= 2) {
    //         User key = userList.get(userList.size() - 1);
    //         User value = userList.get(userList.size() - 2);
    //         userMap.put(key, value);
    //         userMap.put(value, key);
    //         userList.remove(key);
    //         userList.remove(value);
    //     }
    //     User opponent = userMap.get(user);
    //     if (opponent == null){
    //         // 3秒发送一次请求
    //         return CompletableFuture.completedFuture(Result.success("人数不足请等待", null));
    //     }
    //     return CompletableFuture.completedFuture(Result.success("匹配成功", opponent));
    // }
}
